﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Red.GameData.Raw
{
    /// <summary>
    /// A little bit higher level interface to work with Raw.DataObject
    /// Note that it sill does not contain any Reflection related stuff (you need Editor.EditorObjectView for that)
    /// The only advantage of this class is that is contains a good representation of the object's hierarchy (base -> child)
    /// NOTE: this view is cheap to create (much cheaper than Editor.EditorObjectView)
    /// NOTE: this is mostly used to display object's hierarchies without full evaluation via editor view's
    /// </summary>
    public class DataObjectView
    {
        /// <summary>
        /// The raw DataObject this view was created for
        /// </summary>
        public DataObject RawData { get; private set;} // set only once

        /// <summary>
        /// Evaluated (flattened) class name of the object
        /// </summary>
        public string ClassName { get; private set; } // extracted via property or inherited

        /// <summary>
        /// Evaluated (flattened) name of the key property that should be used to retrieve object's name
        /// NOTE: the actual name is NOT cached here
        /// </summary>
        public string KeyProperty {get; private set; }

        /// <summary>
        /// Parent (base) object we derive some of our values from
        /// May be null
        /// </summary>
        public DataObjectView Parent { get { return _Parent; } set { BindParent(value); } }

        /// <summary>
        /// A child (derived) objects
        /// NOTE: this is expensive to find
        /// </summary>
        public List<DataObjectView> Children { get; private set; }

        /// <summary>
        /// Initialize view
        /// </summary>
        /// <param name="parent">Parent data object VIEW</param>
        /// <param name="className">Name of (resolved) calss/param>
        /// <param name="keyPropertyName">Name of the (resolved) key property</param>
        /// <param name="raw">Raw object</param>
        internal DataObjectView(string className, string keyPropertyName, DataObject raw)
        {
            KeyProperty = keyPropertyName;
            ClassName = className;
            RawData = raw;
            _Parent = null;
            Children = new List<DataObjectView>();
        }

        /// <summary>
        /// Change the parent view of this view
        /// </summary>
        /// <param name="view">New parent view to set</param>
        private void BindParent(DataObjectView view)
        {
            if (view != _Parent)
            {
                if (_Parent != null)
                    _Parent.Children.Remove(this);

                _Parent = view;

                if (_Parent != null)
                    _Parent.Children.Add(this);
            }
        }

        /// <summary>
        /// Get object name
        /// NOTE: this evaluates the actual object's property since the name is NEVER cached here
        /// </summary>
        public string Name
        {
            get
            {
                var prop = RawData.GetPropertyNoCreate(KeyProperty);
                if (prop != null)
                {
                    // get the last value
                    if (prop.Values.Count > 0)
                    {
                        return prop.Values[prop.Values.Count - 1].Value;
                    }
                }

                // fallback to a safe name
                return ClassName + "_" + Utils.FormatGuid(RawData.ID);
            }
            set
            {
                // propagate the property change to the raw object
                var currentName = Name;
                if (value != currentName)
                {
                    var prop = RawData.GetProperty(KeyProperty);
                    prop.Action_ModifyValue(value);
                }
            }
        }

        /// <summary>
        /// Parent view (direct pointer)
        /// </summary>
        private DataObjectView _Parent;
    }
}
